using System;
using System.Web;
using System.Text.RegularExpressions;
using System.IO;
using Moxiecode.TinyMCE.Configuration;

namespace Moxiecode.TinyMCE.Compression 
{
	public class GzipModule : Moxiecode.TinyMCE.Web.HttpPipeline.IModule
    {
        #region Fields
        private HttpRequest request;
        private HttpResponse response;
        private HttpServerUtility server;
        private GzipCompressor gzipCompressor = new GzipCompressor();
        private TinyConfigSection configSection;
        private string[] languages = new string[0];
        private string[] themes = new string[0];
        private string[] plugins = new string[0];
        private string installPath;
        private string fileName;
        private string encoding = String.Empty;
        private bool supportsGzip = true;
        #endregion

        public void ProcessRequest(HttpContext context)
        {

            // Set Class Variables 
            request = context.Request;
            response = context.Response;
            server = context.Server;
            configSection = (TinyConfigSection)System.Web.Configuration.WebConfigurationManager.GetSection("TinyMCE");
            if (request.QueryString["languages"] != null) languages = request.QueryString["languages"].Split(',');
            if (request.QueryString["themes"] != null) themes = request.QueryString["themes"].Split(',');
            if (request.QueryString["plugins"] != null) plugins = request.QueryString["plugins"].Split(',');

            // RemoveTrailingSlash since plugins/tinymce expect a base url without a slash 
            installPath = VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.ToAbsolute(configSection.InstallPath));
            fileName = String.IsNullOrEmpty(configSection.Suffix) ? configSection.FileName + ".js" : configSection.FileName + "_" + configSection.Suffix + ".js";
            
            // Create File
            Setup();
            SetGzipSupport();
            IncludeCore();
            IncludeLanguages();
            IncludeThemes();
            IncludePlugins();
            
            // Compress
            Compress();
        }

        #region Create File

        protected void Setup()
        {
            // Set response headers
            response.ContentType = "text/javascript";
            response.Charset = "UTF-8";
            response.Buffer = false;

            // Setup cache
            response.Cache.SetExpires(DateTime.Now.AddTicks(configSection.GzipCompressor.ExpiresOffset));
            response.Cache.SetCacheability(HttpCacheability.Public);
            response.Cache.SetValidUntilExpires(false);
        }

        protected void SetGzipSupport()
        {
            encoding = Regex.Replace("" + request.Headers["Accept-Encoding"], @"\s+", "").ToLower();
            supportsGzip = encoding.IndexOf("gzip") != -1 || request.Headers["---------------"] != null;
            encoding = encoding.IndexOf("x-gzip") != -1 ? "x-gzip" : "gzip";
        }

        protected void IncludeCore()
        {
            string suffix = String.IsNullOrEmpty(configSection.Suffix) ? "" : configSection.Suffix;
            string data = "var tinyMCEPreInit = { base : '" + installPath + "', suffix : '" + suffix + "' };";
            gzipCompressor.AddData(data);
            gzipCompressor.AddFile(server.MapPath(VirtualPathUtility.AppendTrailingSlash(installPath) + fileName));
        }

        protected void IncludeLanguages()
        {
            foreach (string lang in languages)
                gzipCompressor.AddFile(server.MapPath(installPath + "/langs/" + lang + ".js"));
        }

        protected void IncludeThemes()
        {
            foreach (string theme in themes)
            {
                gzipCompressor.AddFile(server.MapPath(installPath + "/themes/" + theme + "/editor_template.js"));

                // Add theme languages
                if (languages != null)
                {
                    foreach (string lang in languages)
                    {
                        string path = server.MapPath(installPath + "/themes/" + theme + "/langs/" + lang + ".js");

                        if (File.Exists(path))
                            gzipCompressor.AddFile(path);
                    }
                }

                gzipCompressor.AddData("tinymce.ThemeManager.urls['" + theme + "'] = tinymce.baseURL+'/themes/" + theme + "';");
            }
        }

        protected void IncludePlugins()
        {
            foreach (string plugin in plugins)
            {
                gzipCompressor.AddFile(server.MapPath(installPath + "/plugins/" + plugin + "/editor_plugin.js"));

                // Add plugin languages
                foreach (string lang in languages)
                {
                    string path = server.MapPath(installPath + "/plugins/" + plugin + "/langs/" + lang + ".js");

                    if (File.Exists(path))
                        gzipCompressor.AddFile(path);
                }

                gzipCompressor.AddData("tinymce.ThemeManager.urls['" + plugin + "'] = tinymce.baseURL+'/plugins/" + plugin + "';");
            }
        }
        
        #endregion

        protected void Compress()
        {
            gzipCompressor.NoCompression = !supportsGzip || configSection.GzipCompressor.NoCompression;
			if (!gzipCompressor.NoCompression) response.AppendHeader("Content-Encoding", encoding);
			gzipCompressor.DiskCache = configSection.GzipCompressor.DiskCache;
			gzipCompressor.CachePath = configSection.GzipCompressor.CachePath;
			gzipCompressor.Compress(response.OutputStream);
        }
    }
}
